﻿using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using Castle.ActiveRecord.Framework;
using FileManager_Server.BusinessLogic.IRepository_Service;
using FileManager_Server.DataLayer.Castle_Model;
using FileManager_Server.DataLayer.Repository;
using FileManager_Server.ServiceModel.DataTransfer_Model;
using FileManager_Server.ServiceModel.WCF_Args_Model;
using FileManager_Server.Utility;

namespace FileManager_Server.BusinessLogic.Respository_Service
{
    public class UserService : IUserService
    {

        public UserLoginResult Login(UserLoginArgs userLoginArgs)
        {
            var result = new UserLoginResult();
            try
            {
                //result.CompanyId = "111";
                //result.LoginId = "111";
                //result.UserId = "111";
                //result.PeopleName = "测试";
                //return result;
                using(var repository = new Repository())
                {
                    var queryResult = repository.GetSingle<UserDbModel>(x => x.LOGINID.Equals(userLoginArgs.UserName));
                    if(null != queryResult && queryResult.LOGINPASSWORD.Equals(userLoginArgs.UserPass))
                    {
                        if(queryResult.STATUS.Equals("0"))
                            result = Mapper.Map<UserDbModel, UserLoginResult>(queryResult);
                        else
                            result.ResultException = BaseExceptionEnum.AccountLock;
                    }
                    else
                        result.ResultException = BaseExceptionEnum.UserNameOrPassError;
                }
            }
            catch (Exception ex)
            {
                LogLoader.Instance.Log.Error("Login has problem:", ex);
                result.ResultException = BaseExceptionEnum.LogicException;
            }
            return result;
        }

        public CompanyResultCollection GetCompanyCollection()
        {
            var result = new CompanyResultCollection();
            try
            {
                //result.CompanyResults = new List<CompanyResult>
                //                            {
                //                                new CompanyResult
                //                                    {
                //                                        CompanyName = "局财务处",
                //                                        Id = "474ac828-7e32-472e-860b-f3860669a667",
                //                                        Pid = "0",
                //                                        ShortName = "局财务处"
                //                                    },
                //                                    new CompanyResult
                //                                        {
                //                                            CompanyName = "综合科",
                //                                            Id = "111",
                //                                            Pid = "474ac828-7e32-472e-860b-f3860669a667",
                //                                            ShortName = "综合科"
                //                                        }
                //                            };
                //return result;
                using (var repository = new Repository())
                {
                    //474ac828-7e32-472e-860b-f3860669a667
                    var queryResult = repository.GetAll<Company>(x => (x.ID.Equals("474ac828-7e32-472e-860b-f3860669a667")
                        || x.PID.Equals("474ac828-7e32-472e-860b-f3860669a667"))&&!x.STATUS);
                    if (null != queryResult)
                        result.CompanyResults = Mapper.Map<IList<Company>, List<CompanyResult>>(queryResult);
                }
            }
            catch (Exception ex)
            {
                LogLoader.Instance.Log.Error("Login has problem:", ex);
                result.ResultException = BaseExceptionEnum.GetCompanyCollectionException;
            }
            return result;
        }

        private void SetCache()
        {
            using (var repository = new Repository())
            {
                var queryCompanyGroup = repository.GetAll<CompanyGroup>();
                var cacheCompanyGroup =
                    Mapper.Map<IList<CompanyGroup>, List<CompanyGroupResult>>(queryCompanyGroup);
                CacheGlobal.Add(GlobalString.System_Config_String.CacheCompanyGroupCollection, cacheCompanyGroup);
                var queryUserGroup = repository.GetAll<UserGroup>();
                var cacheUserGroup =
                  Mapper.Map<IList<UserGroup>, List<UserGroupResult>>(queryUserGroup);
                CacheGlobal.Add(GlobalString.System_Config_String.CacheUserGroupCollection, cacheUserGroup);
                var queryComapny = from a in ActiveRecordLinq.AsQueryable<Company>()
                                   where !(from b in ActiveRecordLinq.AsQueryable<Company>()
                                           where b.ORDERNUMBER.StartsWith("DY")
                                           select b.ID).Contains(a.ID)
                                   select new CompanyResult
                                   {
                                       CompanyName = a.NAME ?? "",
                                       Id = a.ID ?? "",
                                       Pid = a.PID ?? "",
                                       ShortName = a.SHORTNAME ?? "",
                                       Sncode = a.SNCODE ?? ""
                                   };
                var cacheCompany = queryComapny.ToList();
                CacheGlobal.Add(GlobalString.System_Config_String.CacheCompanyCollection, cacheCompany);
            }
        }

        private List<CompanyGroupResult> cacheCompanyGroup;
        private List<UserGroupResult> cacheUserGroup;
        private List<CompanyResult> cacheCompany;
        private List<string> ReturnAllCompanyGroup(IEnumerable<string> companyGroup)
        {
            CheckCache();
            companyGroup = companyGroup.Distinct().ToList();
            var allCompanyGroup = ReturnParentCompanyGroup(companyGroup);
            return allCompanyGroup;
        }
        private List<string> ReturnParentCompanyGroup(IEnumerable<string> spidCollection)
        {
            var result = new List<string>();
            var parentList = cacheCompanyGroup.Where(x => spidCollection.Contains(x.Sid));
            if (parentList.Any())
            {
                result = parentList.Select(x => x.Sid).Distinct().ToList();
                var listGroup = parentList.Select(x => x.Spid).Distinct().ToList();
                var temp = ReturnParentCompanyGroup(listGroup);
                result.AddRange(temp);
            }
            return result;
        }
        private List<string> ReturnAllUserGroup(IEnumerable<string> userGroup)
        {
            CheckCache();
            userGroup = userGroup.Distinct().ToList();
            var allUserGroup = ReturnParentUserGroup(userGroup);
            return allUserGroup;
        }
        private List<string> ReturnParentUserGroup(IEnumerable<string> userGroup)
        {
            var result = new List<string>();
            var parentList = cacheUserGroup.Where(x => userGroup.Contains(x.Sid));
            if (parentList.Any())
            {
                result = parentList.Select(x => x.Sid).Distinct().ToList();
                var listGroup = parentList.Select(x => x.Spid).Distinct().ToList();
                var temp = ReturnParentUserGroup(listGroup);
                result.AddRange(temp);
            }
            return result;
        }

        private List<string> ReturnCompany(string comapny)
        {
            CheckCache();
            var parentCompany = cacheCompany.FirstOrDefault(x => x.Id.Equals(comapny)).Pid;
            var allCompany = ReturnAllCompany(new List<string>{parentCompany});
            return allCompany;
        }
        private List<string> ReturnAllCompany(ICollection<string> comapny)
        {
            var result = new List<string>();
            var parentList = cacheCompany.Where(x => comapny.Contains(x.Id));
            if (parentList.Any())
            {
                result = parentList.Select(x => x.Id).Distinct().ToList();
                var listGroup = parentList.Select(x => x.Pid).Distinct().ToList();
                var temp = ReturnAllCompany(listGroup);
                result.AddRange(temp);
            }
            return result;
        }


        private void CheckCache()
        {
            cacheCompanyGroup =
         CacheGlobal.GetCache(GlobalString.System_Config_String.CacheCompanyGroupCollection) as
         List<CompanyGroupResult>;
            cacheUserGroup =
                CacheGlobal.GetCache(GlobalString.System_Config_String.CacheUserGroupCollection) as
                List<UserGroupResult>;
            cacheCompany =
                CacheGlobal.GetCache(GlobalString.System_Config_String.CacheCompanyCollection) as
                List<CompanyResult>;
            if (null != cacheCompany) return;
            SetCache();
            cacheCompanyGroup =
                CacheGlobal.GetCache(GlobalString.System_Config_String.CacheCompanyGroupCollection) as
                List<CompanyGroupResult>;
            cacheUserGroup =
                CacheGlobal.GetCache(GlobalString.System_Config_String.CacheUserGroupCollection) as
                List<UserGroupResult>;
            cacheCompany =
                CacheGlobal.GetCache(GlobalString.System_Config_String.CacheCompanyCollection) as
                List<CompanyResult>;
        }
        public FolderRoleResultCollection GetFolderRoleCollection(FolderRoleQueryArgs folderRoleQueryArgs)
        {
            var result = new FolderRoleResultCollection();
            try
            {
                using (var repository = new Repository())
                {
                    var groupMemberId = repository.GetAll<CompanyGroupMember>(x => x.COMPANYID.Equals(folderRoleQueryArgs.CompanyId)).Select(x=>x.GROUPID).ToList();
                    var companyGroupCollection = repository.GetAll<CompanyGroup>(x => groupMemberId.Contains(x.GROUPID)).ToList();
                    var allParnetCompanyGroupCollection =
                        ReturnAllCompanyGroup(companyGroupCollection.Select(x => x.SPID).ToList());
                    var tempCompanyGroup = companyGroupCollection.Select(x => x.SID).ToList();
                    allParnetCompanyGroupCollection.AddRange(tempCompanyGroup);
                    var allCompanyGroupCollection = allParnetCompanyGroupCollection.Distinct().ToList();

                    var userMemberId =
                        repository.GetAll<UserGroupMember>(x => x.USERID.Equals(folderRoleQueryArgs.UserId)).Select(x => x.GROUPID).ToList();
                    var userGroupCollection = repository.GetAll<UserGroup>(x => userMemberId.Contains(x.ID)).ToList();
                    var allParnetUserGroupCollection =
                        ReturnAllUserGroup(userGroupCollection.Select(x => x.SPID));
                    var tempUserGroup = userGroupCollection.Select(x => x.SID).ToList();
                    allParnetUserGroupCollection.AddRange(tempUserGroup);
                    var allUserGroupCollection = allParnetUserGroupCollection.Distinct().ToList();
                    var allCompanyCollection = ReturnCompany(folderRoleQueryArgs.CompanyId);
                    allCompanyCollection.Add(folderRoleQueryArgs.CompanyId);

                    var queryResultFolder = repository.GetAll<FileDbModel>(x => !x.ISFILE).Select(x => x.FILESID).ToList();
                    var queryResult = repository.GetAll<FileRoleDbModel>(x => queryResultFolder.Contains(x.FILESID)&&
                                                                         ((x.ROLETYPE.Equals(RoleTypeArgs.User) &&
                                                                          x.RELATIONID.Equals(folderRoleQueryArgs.UserId))
                                                                         ||
                                                                         (x.ROLETYPE.Equals(RoleTypeArgs.UserGroup) &&
                                                                          allUserGroupCollection.Contains(x.RELATIONID))
                                                                         ||
                                                                         (x.ROLETYPE.Equals(RoleTypeArgs.Company) &&
                                                                          allCompanyCollection.Contains(x.RELATIONID))
                                                                         ||
                                                                         (x.ROLETYPE.Equals(RoleTypeArgs.CompanyGroup) &&
                                                                          allCompanyGroupCollection.Contains(x.RELATIONID))
                                                                         || (x.ROLETYPE.Equals(RoleTypeArgs.AnyOne)))).ToList();
                    var fileSidCollection = queryResult.Select(x => x.FILESID).Distinct().ToList();
                    result.RoleResults = new List<FolderRoleResult>();
                    foreach (var fileSid in fileSidCollection)
                    {
                        var fileRoleCollection = queryResult.Where(x => x.FILESID.Equals(fileSid)).ToList();
                        var folderRole = new FolderRoleResult { FileId = fileSid, IsCreate = false, IsDelete = false, IsJustMe = false, IsRead = false, IsUpdate = false };
                        foreach (var fileRoleDbModel in fileRoleCollection)
                        {
                            folderRole.IsCreate = folderRole.IsCreate | fileRoleDbModel.ISCREATE;
                            folderRole.IsDelete = folderRole.IsDelete | fileRoleDbModel.ISDELETE;
                            folderRole.IsJustMe = folderRole.IsJustMe | fileRoleDbModel.ISOWNER;
                            folderRole.IsRead = folderRole.IsRead | fileRoleDbModel.ISREAD;
                            folderRole.IsUpdate = folderRole.IsUpdate | fileRoleDbModel.ISUPDATE;
                            result.RoleResults.Add(folderRole);
                        }
                    }
                    result.RoleResults = result.RoleResults.Where(x => queryResultFolder.Contains(x.FileId)).ToList();
                    //result.RoleResults = Mapper.Map<IList<FileRoleDbModel>, List<FolderRoleResult>>(queryResult);
                }
            }
            catch (Exception ex)
            {
                LogLoader.Instance.Log.Error("GetFolderRoleCollection has problem:", ex);
                result.ResultException = BaseExceptionEnum.GetFolderRoleCollectionException;
            }
            return result;
        }


        public UserResultCollection SearchUserByName(SearchUserNameArgs searchUserNameArgs)
        {
            var result = new UserResultCollection();
            try
            {
                using (var repository = new Repository())
                {
                    var queryResult = from a in ActiveRecordLinq.AsQueryable<UserDbModel>()
                                      join b in ActiveRecordLinq.AsQueryable<Company>()
                                          on a.COMPANYID equals b.SID
                                      where a.NAME.Contains(searchUserNameArgs.NameKey)
                                      select new UserResult
                                                 {
                                                     CompanyId = b.SID,
                                                     CompanyName = b.SHORTNAME,
                                                     UserId = a.USERID,
                                                     UserName = a.NAME
                                                 };
                    result.Result = queryResult.ToList();
                }
            }
            catch (Exception ex)
            {
                LogLoader.Instance.Log.Error("SearchUserByName has problem:", ex);
                result.ResultException = BaseExceptionEnum.SearchUserException;
            }
            return result;
        }


        public CompanGroupAndUserGroupResultCollection GetCompanyGroupAndUserGroupCollection()
        {
            var result = new CompanGroupAndUserGroupResultCollection();
            try
            {
                using (var repository = new Repository())
                {
                    CheckCache();
                    result.CompanyGroupResults = cacheCompanyGroup;
                    result.UserGroupResults = cacheUserGroup;
                    result.CompanyResults = cacheCompany;
                }
            }
            catch (Exception ex)
            {
                LogLoader.Instance.Log.Error("GetCompanyGroupAndUserGroupCollection has problem:", ex);
                result.ResultException = BaseExceptionEnum.GetCompanyGroupAndUserGroupCollectionExpcetion;
            }
            return result;
        }


        public UserResultCollection SearchUserByCompanyCode(SearchUserByCompanyCodeArgs searchUserByCompanyCodeArgs)
        {
            var result = new UserResultCollection();
            try
            {
                using (var repository = new Repository())
                {
                    IEnumerable<UserResult> queryResult = new UserResult[0];
                    switch (searchUserByCompanyCodeArgs.SearchUserByCompanyEnum)
                    {
                            case SearchUserByCompanyEnum.CompanyGroup:
                            var tempCollection = searchUserByCompanyCodeArgs.CodeCollection.Select(int.Parse).ToList();
                            queryResult = from a in ActiveRecordLinq.AsQueryable<UserDbModel>()
                                              join b in ActiveRecordLinq.AsQueryable<Company>()
                                                  on a.COMPANYID equals b.SID
                                              where (from c in ActiveRecordLinq.AsQueryable<CompanyGroupMember>()
                                                     where tempCollection.Contains(c.GROUPID)
                                                         select c.COMPANYID).Contains(a.COMPANYID)
                                              select new UserResult
                                              {
                                                  CompanyId = b.SID,
                                                  CompanyName = b.SHORTNAME,
                                                  UserId = a.SID,
                                                  UserName = a.NAME
                                              };
                            break;
                            case SearchUserByCompanyEnum.Company:
                            queryResult = from a in ActiveRecordLinq.AsQueryable<UserDbModel>()
                                          join b in ActiveRecordLinq.AsQueryable<Company>()
                                              on a.COMPANYID equals b.SID
                                          where searchUserByCompanyCodeArgs.CodeCollection.Contains(a.COMPANYID)
                                          select new UserResult
                                          {
                                              CompanyId = b.SID,
                                              CompanyName = b.SHORTNAME,
                                              UserId = a.SID,
                                              UserName = a.NAME
                                          };
                            break;
                            case SearchUserByCompanyEnum.UserGroup:
                            var tempCollectionUserByCompany = searchUserByCompanyCodeArgs.CodeCollection.Select(int.Parse).ToList();
                            queryResult = from a in ActiveRecordLinq.AsQueryable<UserDbModel>()
                                          join b in ActiveRecordLinq.AsQueryable<Company>()
                                              on a.COMPANYID equals b.SID
                                          where (from c in ActiveRecordLinq.AsQueryable<UserGroupMember>()
                                                 where tempCollectionUserByCompany.Contains(c.GROUPID)
                                                 select c.USERID).Contains(a.USERID)
                                          select new UserResult
                                          {
                                              CompanyId = b.SID,
                                              CompanyName = b.SHORTNAME,
                                              UserId = a.SID,
                                              UserName = a.NAME
                                          };
                            break;
                    }
                    result.Result = queryResult.ToList();
                }
            }
            catch (Exception ex)
            {
                LogLoader.Instance.Log.Error("SearchUserByCompanyCode has problem:", ex);
                result.ResultException = BaseExceptionEnum.SearchUserByCompanyCodeException;
            }
            return result;
        }
    }

    public static class RoleTypeArgs
    {
        public const string User = "0";
        public const string UserGroup = "2";
        public const string Company = "1";
        public const string CompanyGroup = "3";
        public const string AnyOne = "5";
    }
}